/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bff.core.action.retrievedefault;

import com.inspur.edp.bef.api.lcp.IStandardLcp;
import com.inspur.edp.bff.api.dataprocessor.IDataConvertor;
import com.inspur.edp.bff.api.extend.IBffEntityExtend;
import com.inspur.edp.bff.api.extend.IBffManagerExtend;
import com.inspur.edp.bff.api.manager.IFSManager;
import com.inspur.edp.bff.api.manager.IFSManagerContext;
import com.inspur.edp.bff.api.manager.assembler.IAssemblerManager;
import com.inspur.edp.bff.api.manager.assembler.IExtendRetrieveDefaultChildAssembler;
import com.inspur.edp.bff.api.manager.context.RetrieveDefaultChildContext;
import com.inspur.edp.bff.spi.AbstractDataConvertor;
import com.inspur.edp.bff.spi.AbstractFSAction;
import com.inspur.edp.bff.spi.assembler.AbstractAssemblerManager;
import com.inspur.edp.bff.spi.builtin.BffEntityResInfoImpl;
import com.inspur.edp.bff.spi.builtin.BffModelResInfoImpl;
import com.inspur.edp.bff.spi.builtin.BffPropertyInfo;
import com.inspur.edp.bff.spi.defaultvalue.DefaultValueUtil;
import com.inspur.edp.cef.api.changeListener.EntityDataChangeListener;
import com.inspur.edp.cef.api.dataType.entity.ICefEntity;
import com.inspur.edp.cef.entity.accessor.entity.IEntityAccessor;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.changeset.ModifyChangeDetail;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.ModelResInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefEntityResInfoImpl;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefModelResInfoImpl;
import lombok.var;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RetrieveDefaultChildAction extends AbstractFSAction<IEntityData> {

    private ArrayList<String> nodeCodes;
    private ArrayList<String> lierachyIds;

    public RetrieveDefaultChildAction(ArrayList<String> nodeCodes, ArrayList<String> lierachyIds) {
        this.nodeCodes = nodeCodes;
        this.lierachyIds = lierachyIds;
    }

    @Override
    protected void execute() {
        IExtendRetrieveDefaultChildAssembler assemblerMgr = getAssembler();
        if (assemblerMgr == null) {
            doDefaultRetrieveDefault();
            return;
        }

        RetrieveDefaultChildContext actionCtx = new RetrieveDefaultChildContext();
        actionCtx.setNodeCodes(nodeCodes);
        actionCtx.setHierachyIds(lierachyIds);

        //① BeforeRetrieve
//        assemblerMgr.doBeforeRetrieveDefault(getContext(), actionCtx);

        //② DoRetrieve
        assemblerMgr.doRetrieveDefault(getContext(), actionCtx);
        //③ DataMapping TODO: 子表映射暂不实现
        ArrayList<IEntityData> vmDatas = actionCtx.getRetrieveDefaultData().values().iterator().next();

        //处理虚拟字段默认值
        if (getModelInfo() instanceof BffModelResInfoImpl) {
            dealVirtualDefaultValue(vmDatas.get(0), getContext());
        }
        actionCtx.setRetrieveDefaultResult(vmDatas.get(0));
        //④ AfterRetrieve
//        assemblerMgr.doAfterRetrieveDefault(getContext(), actionCtx);

        setResult(vmDatas.get(0));
    }

    private IExtendRetrieveDefaultChildAssembler getAssembler() {
        IAssemblerManager assemblerManager = getContext().getAssemblerManager();
        if (assemblerManager == null || !(assemblerManager instanceof AbstractAssemblerManager)) {
            return null;
        }
        return ((AbstractAssemblerManager) assemblerManager).getRetrieveDefaultChildAssembler();
    }

    private void doDefaultRetrieveDefault() {
        IEntityData beData;
        ModelResInfo modelResInfo = this.getModelInfo();
        if (modelResInfo instanceof BffModelResInfoImpl) {
            Map<String, Object> defaultValues = new HashMap<>();
            initDefaultValue(getContext().getBffManager(), getLcp(), defaultValues, nodeCodes);
            beData = getLcp().retrieveDefaultChild(nodeCodes, lierachyIds, defaultValues);
        } else {
            beData = getLcp().retrieveDefaultChild(nodeCodes, lierachyIds);
        }
        AbstractDataConvertor dataConvertor = getDataConvertor(nodeCodes);
        Object tempVar = getContext().getBffManager().createChildData(nodeCodes.get(nodeCodes.size() - 1), "");

        IEntityAccessor vmAccessor = (IEntityAccessor) ((tempVar instanceof IEntityAccessor) ? tempVar : null);

        IEntityData voData = (IEntityData) ((vmAccessor.getInnerData() instanceof IEntityData) ? vmAccessor.getInnerData() : null);

        if (dataConvertor != null)
            dataConvertor.convertFromBEData(beData, voData);

        //region extend
        dealExtendMapping(voData, beData);

        vmAccessor.setInnerData(voData);
        if (!(modelResInfo instanceof BffModelResInfoImpl)) {
            dealDefaultValue(vmAccessor);
        }
        IEntityData result = (IEntityData) ((vmAccessor.getInnerData() instanceof IEntityData) ? vmAccessor.getInnerData() : null);
        //默认值
        if (modelResInfo instanceof BffModelResInfoImpl) {
            dealVirtualDefaultValue(result, getContext());
        }
        setResult(result);
    }

    private ModelResInfo getModelInfo() {
        return this.getContext().getModelResourceInfo();
    }

    private void dealVirtualDefaultValue(IEntityData data, IFSManagerContext context) {
        ModelResInfo modelResInfo = context.getModelResourceInfo();
        if (modelResInfo != null && modelResInfo instanceof CefModelResInfoImpl && ((CefModelResInfoImpl) modelResInfo).getEntityResInfos().containsKey(nodeCodes.get(nodeCodes.size() - 1).toLowerCase())) {
            BffEntityResInfoImpl resInfo = (BffEntityResInfoImpl) modelResInfo.getCustomResource(nodeCodes.get(nodeCodes.size() - 1));
            Map<String, DataTypePropertyInfo> propertyInfos = resInfo.getEntityTypeInfo().getPropertyInfos();
            if (propertyInfos == null || propertyInfos.size() == 0)
                return;
            for (Map.Entry<String, DataTypePropertyInfo> propInfo : propertyInfos.entrySet()) {
                String beLabelId = ((BffPropertyInfo) (propInfo.getValue())).getBeLabelId();
                if (beLabelId != null && !"".equals(beLabelId))
                    continue;
                if ((propInfo.getValue()).getDefaultValue() != null) {
                    data.setValue((propInfo.getValue()).getPropertyName(), (propInfo.getValue()).getDefaultValue().getRealValue());
                }

            }
        }
    }

    public void mergeDefaultValue(Map<String, Object> outerValue, Map<String, Object> innerDefaultValue) {
        if (outerValue == null || outerValue.size() == 0)
            return;
        for (Map.Entry<String, Object> defaultValue : outerValue.entrySet()) {
            innerDefaultValue.put(defaultValue.getKey(), defaultValue.getValue());
        }
    }

    private void initDefaultValue(IFSManager manager, IStandardLcp lcp, Map<String, Object> values, ArrayList<String> nodeCodes) {
        List<IBffManagerExtend> extendList = manager.getBffContext().getExtList();
        ModelResInfo modelResInfo = getContext().getBffManager().getModelInfo();
        if (modelResInfo instanceof CefModelResInfoImpl && ((CefModelResInfoImpl) modelResInfo).getEntityResInfos().containsKey(nodeCodes.get(nodeCodes.size() - 1).toLowerCase())) {
            initBasicDefaultValue(manager, lcp, values, nodeCodes);
            if (extendList == null || extendList.size() == 0)
                return;
            initChangedDefaultValue(manager, lcp, values, extendList, nodeCodes);
            mapExtendDefaultValue(manager, extendList, values, nodeCodes);
            return;
        }
        mapExtendDefaultValue(manager, extendList, values, nodeCodes);
    }

    private void mapExtendDefaultValue(IFSManager manager, List<IBffManagerExtend> extendList, Map<String, Object> values, ArrayList<String> nodeCodes) {
        Map<String, Object> extendDefaultValues = new HashMap<>();
        Map<String, Object> beDefaultValues = new HashMap<>();
        for (IBffManagerExtend bffManagerExtend : extendList) {
            IBffEntityExtend bffEntityExtend = getChildEntityExtend(bffManagerExtend);
            if (bffEntityExtend != null) {
                //VO扩展默认值
                initExtendDefaultValue(manager, bffEntityExtend, extendDefaultValues, nodeCodes);
                //转换扩展默认值
                bffEntityExtend.mapDefaultValuesFromVo(extendDefaultValues, beDefaultValues);
                //合并默认值
            }
        }
        mergeDefaultValue(beDefaultValues, values);
    }

    private void initExtendDefaultValue(IFSManager manager, IBffEntityExtend extend, Map<String, Object> values, ArrayList<String> nodeCodes) {
        CefEntityResInfoImpl entityResInfo = extend.getEntityResInfo();
        if (entityResInfo == null || entityResInfo.getEntityTypeInfo() == null || entityResInfo.getEntityTypeInfo().getPropertyInfos() == null)
            return;
        for (Map.Entry<String, DataTypePropertyInfo> propInfo : entityResInfo.getEntityTypeInfo().getPropertyInfos().entrySet()) {
            DataTypePropertyInfo propertyInfo = propInfo.getValue();
            if (propertyInfo.getDefaultValue() == null || ("".equals(propertyInfo.getDefaultValue().getRealValue()) || propertyInfo.getDefaultValue().getRealValue() == null))
                continue;
            DefaultValueUtil.dealExtendValue(manager, propertyInfo, nodeCodes, values);
        }
    }

    private void initBasicDefaultValue(IFSManager manager, IStandardLcp lcp, Map<String, Object> values, ArrayList<String> nodeCodes) {
        CefEntityResInfoImpl resInfo = (CefEntityResInfoImpl) manager.getModelInfo().getCustomResource(nodeCodes.get(nodeCodes.size() - 1));
        if (resInfo.getEntityTypeInfo() == null || resInfo.getEntityTypeInfo().getPropertyInfos() == null || resInfo.getEntityTypeInfo().getPropertyInfos().size() == 0)
            return;
        dealPropDefaultValue(manager, lcp, resInfo.getEntityTypeInfo().getPropertyInfos(), values, nodeCodes);
    }

    private void initChangedDefaultValue(IFSManager manager, IStandardLcp lcp, Map<String, Object> values, List<IBffManagerExtend> extendList, ArrayList<String> nodeCodes) {
        for (IBffManagerExtend bffManagerExtend : extendList) {
            IBffEntityExtend entityExtend = getChildEntityExtend(bffManagerExtend);
            dealChangePropertyValue(manager, lcp, entityExtend, values, nodeCodes);
        }
    }

    private void dealChangePropertyValue(IFSManager manager, IStandardLcp lcp, IBffEntityExtend bffEntityDataExtend, Map<String, Object> values, ArrayList<String> nodeCodes) {
        bffEntityDataExtend.mapChangedDefaultValuesFromVo(manager, lcp, nodeCodes, values);
    }

    private void dealPropDefaultValue(IFSManager manager, IStandardLcp lcp, Map<String, DataTypePropertyInfo> prpertyInfos, Map<String, Object> values, ArrayList<String> nodeCodes) {
        for (Map.Entry<String, DataTypePropertyInfo> propertyInfo : prpertyInfos.entrySet()) {
            DataTypePropertyInfo propertyInfoTemp = propertyInfo.getValue();
            String beLabelId = ((BffPropertyInfo) propertyInfoTemp).getBeLabelId();
            if (defaultValueIsNull(propertyInfoTemp))
                continue;
            if (beLabelId == null || "".equals(beLabelId))
                continue;
            DefaultValueUtil.dealDefaultValue(manager, lcp, propertyInfoTemp, nodeCodes, values);
        }
    }

    private boolean defaultValueIsNull(DataTypePropertyInfo propertyInfo) {
        if (propertyInfo.getDefaultValue() == null)
            return true;
        Object value = propertyInfo.getDefaultValue().getRealValue();
        if (value == null || "".equals(value))
            return true;
        return false;
    }

    private void dealExtendMapping(IEntityData voData, IEntityData beData) {
        var extList = getContext().getExtList();
        if (extList == null || extList.size() < 1)
            return;
        for (var ext : extList) {
            IBffEntityExtend entityExtend = getChildEntityExtend(ext);
            if (entityExtend != null)
                entityExtend.mapData2Vo(voData, beData);
        }
    }

    private IBffEntityExtend getChildEntityExtend(IBffManagerExtend mgrExtend) {

        IBffEntityExtend entityExtend = mgrExtend.getDataTypeExtend();
        for (String nodeCode :
                nodeCodes) {
            entityExtend = entityExtend.getChildEntity(nodeCode);
            if (entityExtend == null)
                break;
        }
        return entityExtend;
    }


    private void dealDefaultValue(IEntityAccessor vmAccessor) {

        IEntityData voData = (IEntityData) ((vmAccessor.getInnerData() instanceof IEntityData) ? vmAccessor.getInnerData() : null);

        EntityDataChangeListener listener = EntityDataChangeListener.createInstance();
        listener.registListener((ICefData) ((vmAccessor instanceof ICefData) ? vmAccessor : null));
        ICefEntity entinty = getEntity(voData.getID());
        entinty.assignDefaultValue(vmAccessor);


        IChangeDetail defalutChange = listener.getChange();
        if (defalutChange != null) {
            ModifyChangeDetail beChange = getChangeDetail((ModifyChangeDetail) ((defalutChange instanceof ModifyChangeDetail) ? defalutChange : null));
            getContext().getBffManager().modify(beChange);
        }
    }

    private ModifyChangeDetail getChangeDetail(ModifyChangeDetail defaultChange) {
        IChangeDetail tempVar = defaultChange.clone();

        ModifyChangeDetail currentChange = (ModifyChangeDetail) ((tempVar instanceof ModifyChangeDetail) ? tempVar : null);
        for (int i = lierachyIds.size() - 1; i >= 0; i--) {

            String nodeCode = nodeCodes.get(i);
            ModifyChangeDetail change = new ModifyChangeDetail(lierachyIds.get(i));
            HashMap<String, IChangeDetail> childChange = new HashMap<String, IChangeDetail>();
            childChange.put(currentChange.getDataID(), currentChange);
            change.getChildChanges().put(nodeCode, childChange);
            IChangeDetail tempVar2 = change.clone();
            currentChange = (ModifyChangeDetail) ((tempVar2 instanceof ModifyChangeDetail) ? tempVar2 : null);
        }

        return currentChange;
    }

    private ICefEntity getEntity(String childId) {
        ICefEntity currentEntity = getContext().getBffManager().createEntity(lierachyIds.get(0));
        for (int i = 0; i < nodeCodes.size(); i++) {
            currentEntity = currentEntity.getChildEntity(nodeCodes.get(i), i == nodeCodes.size() - 1 ? childId : lierachyIds.get(i + 1));
        }

        return currentEntity;
    }

    private AbstractDataConvertor getDataConvertor(ArrayList<String> nodesCodes) {
        IDataConvertor tempVar = getContext().getDataConvertor();
        AbstractDataConvertor rootConvertor = (AbstractDataConvertor) ((tempVar instanceof AbstractDataConvertor) ? tempVar : null);
        if (nodeCodes.isEmpty()) {
            return rootConvertor;
        }
        AbstractDataConvertor currentConvertor = rootConvertor;
        for (int i = 0; i < nodeCodes.size(); i++) {
            currentConvertor = (AbstractDataConvertor) currentConvertor.getChildConvertor(nodeCodes.get(i));
            if (currentConvertor == null)
                break;
        }
        return currentConvertor;
    }
}
